<html>
  <head>
    <title>MJPEG-Streamer</title>

    <!-- refresh page after a few seconds, prevents hang-ups -->
    <meta http-equiv="refresh" content="60" />
  </head>

<script language="javascript" type="text/javascript" src="/functions.js"></script>
<script type="text/javascript">

/*******************************************************************************
  Copyright (C) 2009 Tom Stoeveken
  This program is free software;
  you can redistribute it and/or modify it under the terms of the
  GNU General Public License, version 2.
  See the file COPYING for details.
*******************************************************************************/

var img1 = null;
var img2 = null;
var canvas = null;

/*
  compare two images and count the differences

  input.: image1 and image2 are Image() objects
  input.: canvas is a Canvas() object to draw with
  input.: threshold specifies by how much the color value of a pixel
          must differ before they are regarded to be different

  return: number of different pixels
*/
function compare(image1, image2, canvas, threshold) {
  var movement = 0;
  var ctx = canvas.getContext("2d");
  var width = canvas.width/2, height = canvas.height/2;

  // copy images into canvas element
  // these steps scale the images and decodes the image data
  ctx.drawImage(image1, 0, 0, width, height);
  ctx.drawImage(image2, width, 0, width, height);

  // this makes r,g,b,alpha data of images available
  var pixels1 = ctx.getImageData(0, 0, width, height);
  var pixels2 = ctx.getImageData(width, 0, width, height);
  var pixels_diff = ctx.getImageData(0, 0, width, height);

  // substract picture1 from picture2
  // if they differ set color value to max,
  // if the difference is below threshold set difference to 0.
  for (var x = 0; x < pixels1.width; x++) {
    for (var y = 0; y < pixels1.height; y++) {

      // each pixel has a red, green, blue and alpha value
      // all values are stored in a linear array
      var i = x*4 + y*4*pixels1.width;

      pixels_diff.data[i] = (Math.abs(pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
      pixels_diff.data[i+1] = (Math.abs(pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
      pixels_diff.data[i+2] = (Math.abs(pixels1.data[i] - pixels2.data[i])>threshold)?255:0;
      pixels_diff.data[i+3] = 255;

      // count differing pixels
      movement += Math.min(1, pixels_diff.data[i] + pixels_diff.data[i+1] + pixels_diff.data[i+2]);
    }
  }

  ctx.putImageData(pixels_diff, width/2, height);

  return movement;
}

/*
  Callback function for completed picture downloads

  With every new picture a compare() is performed.
  The new picture is 'img1', the previous picture is stored in 'img2'.
*/
function newPictureComplete() {
  // just compare if there are two pictures
  if ( img2 != null ) {
    var res;

    try {
      // compare the two pictures, the given threshold helps to ignore noise
      res = compare(img1, img2, canvas, 50);
    }
    catch(e) {
      // errors can happen if the pictures were corrupted during transfer
      // instead of giving up, just proceed
    }

    // show to the user if we regards this as motion
    // decide for a color depending on movement (more then N pixels)
    // draw into free area of canvas
    // (hardcoded positions for better performance)
    var ctx = canvas.getContext("2d");
    ctx.fillStyle = ( res > 5 ) ? "rgb(200,0,0)" : "rgb(0,200,0)";
    ctx.fillRect (0, 50, 25, 50); ctx.fillRect (75, 50, 25, 50);

    // send server our finding that there was some movement
    if ( res > 5 ) {
      AJAX_get('/?action=command&command=store')
    }
  }

  // copy reference of img1 to img2
  img2 = img1;
  img2.onload = null;
  // load a new picture into img1
  img1 = new Image();
  img1.onload=newPictureComplete;

  // load next picture in a few milliseconds
  // the server blocks anyway until a fresh picture has arrived, so it can never be faster
  // than the framerate. This timeout is intended to have the option
  // to lower the required processing power at client side.
  window.setTimeout("img1.src='/?action=snapshot&unique='+Math.random();", 1);
}

/*
  Initialize the elements

  * Create a Canvas() object and insert it into the page
  * Download the first image
  * Pause the Livestream again if we were paused previously
    This way we will not pause, but we will lower the refresh rate
    For a proper pause, the page can not be reloaded
*/
function run() {
  canvas = document.createElement("canvas");
  canvas.width = 100;
  canvas.height = 100;
  canvas.id = "comparison_canvas";
  document.getElementById("comparison").appendChild(canvas);

  img1 = new Image();
  img1.onload=newPictureComplete;
  img1.src = "/?action=snapshot";

  if ( window.name.indexOf('paused') != -1 )
    play_pause(document.getElementById("stream"));
}

/*
  Callback function for AJAX command

  input.: text is the response of the server
*/
function AJAX_response(text) {
  // nothing to do
  // later we might show a little folder symbol or so that dissapears
  // after a while
}

/*
  can toggle play/pause of the HTTP-push live preview

  input.: 'img' is the Image() object displaying the stream/picture
*/
function play_pause(img) {
  if ( img.src.indexOf('/?action=stream') != -1 ) {
    img.src = "/?action=snapshot&unique="+Math.random();

    // to keep the play/pause state over a page reload
    // this persistent property of the window can be (mis)used
    // it is a simple, but not so clean way of doing it
    // a cookie or server side scripting would be better in order to
    // pass information from one page to the other (reload)
    window.name = 'paused';
  } else {
    img.src = "/?action=stream";
    window.name = 'streaming';
  }
}

</script>
<body onload="run()">

  <fieldset style="background-color: silver; width: 200px; float: left">
    <legend style="background-color: silver; border: 1px solid black">Motion Detection</legend>
    <div id="comparison"></div>
  </fieldset>

  <fieldset style="background-color: silver; width: 50%">
    <legend style="background-color: silver; border: 1px solid black">Livestream</legend>
    <img id="stream" src="/?action=stream" width="100%" onclick="play_pause(this)" />
  </fieldset>

</body>
</html>
